<template>
  <div class="app-container">
    <!-- 搜索表单 -->
    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="80px">
      <el-form-item label="主题ID" prop="topicId">
        <el-input v-model="queryParams.topicId" placeholder="请输入热搜主题ID" clearable @keyup.enter="handleQuery" style="width: 200px;" />
      </el-form-item>
      <el-form-item label="创建时间" prop="createdTime">
        <el-date-picker v-model="queryParams.createdTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择创建时间" clearable />
      </el-form-item>
      <el-form-item label="爬取状态" prop="crawlStatus">
        <el-select v-model="queryParams.crawlStatus" placeholder="请选择爬取状态" clearable style="width: 150px;">
          <el-option v-for="(value, key) in crawlStatusMap" :key="key" :label="value.label" :value="Number(key)" />
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>

    <!-- 操作按钮 -->
    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5" v-for="btn in actionButtons" :key="btn.key">
        <el-button
          :type="btn.type"
          :plain="btn.plain"
          :icon="btn.icon"
          :disabled="btn.disabled"
          @click="btn.handler"
          v-hasPermi="btn.permission"
        >{{ btn.label }}</el-button>
      </el-col>
      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
    </el-row>

    <!-- 数据表格 -->
    <el-table v-loading="loading" :data="related_linksList" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" align="center" />
      <el-table-column label="热搜主题ID" align="center" prop="topicId" />
      <el-table-column label="相关链接URL" align="center" prop="relatedUrl" width="350">
        <template #default="scope">
          <div class="url-container">
            <el-tooltip :content="scope.row.relatedUrl" placement="top">
              <span class="url-text">{{ truncateUrl(scope.row.relatedUrl) }}</span>
            </el-tooltip>
            <el-button
              type="primary"
              size="small"
              icon="DocumentCopy"
              circle
              @click="copyToClipboard(scope.row.relatedUrl)"
              class="copy-btn"
              title="复制链接"
            />
          </div>
        </template>
      </el-table-column>
      <el-table-column label="爬取状态" align="center" prop="crawlStatus">
        <template #default="scope">
          <el-tag :type="crawlStatusMap[scope.row.crawlStatus]?.type">
            {{ crawlStatusMap[scope.row.crawlStatus]?.label }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="创建时间" align="center" prop="createdTime" width="180">
        <template #default="scope">
          <span>{{ parseTime(scope.row.createdTime, '{y}-{m}-{d}') }}</span>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template #default="scope">
          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['related_links:related_links:edit']">修改</el-button>
          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['related_links:related_links:remove']">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    
    <!-- 分页 -->
    <pagination
      v-show="total > 0"
      :total="total"
      v-model:page="queryParams.pageNum"
      v-model:limit="queryParams.pageSize"
      @pagination="getList"
    />

    <!-- 修改对话框 -->
    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
      <el-form ref="related_linksRef" :model="form" :rules="rules" label-width="100px">
        <el-form-item label="热搜主题ID" prop="topicId">
          <el-input v-model="form.topicId" placeholder="请输入热搜主题ID" disabled />
        </el-form-item>
        <el-form-item label="相关链接URL" prop="relatedUrl">
          <el-input v-model="form.relatedUrl" type="textarea" placeholder="请输入内容" />
        </el-form-item>
        <el-form-item label="爬取状态" prop="crawlStatus">
          <el-select v-model="form.crawlStatus" placeholder="请选择爬取状态">
            <el-option
              v-for="(value, key) in crawlStatusMap"
              :key="key"
              :label="value.label"
              :value="Number(key)"
            />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">确 定</el-button>
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>
    
    <!-- 爬虫进度弹窗 -->
    <el-dialog 
      title="爬虫进度" 
      v-model="crawlerProgressVisible" 
      width="600px" 
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      @close="handleProgressDialogClose"
    >
      <div class="progress-container">
        <!-- 当前状态显示 -->
        <div class="status-section">
          <el-tag :type="statusConfig[crawler.status]?.type" size="large">
            <el-icon><Clock /></el-icon>
            {{ statusConfig[crawler.status]?.label }}
          </el-tag>
          <span class="status-time">{{ currentTime }}</span>
        </div>

        <!-- 总体进度 -->
        <div class="progress-section">
          <h4>总体进度</h4>
          <el-progress 
            :percentage="overallPercentage" 
            :status="progressStatus"
            :stroke-width="12"
          />
          <div class="progress-text">
            已处理: {{ crawler.processed }} / {{ crawler.total || 0 }}
          </div>
        </div>

        <!-- 详细统计 -->
        <div class="stats-section">
          <div class="stat-item success">
            <el-icon><Check /></el-icon>
            <span class="stat-label">成功</span>
            <span class="stat-value">{{ crawler.success || 0 }}</span>
          </div>
          <div class="stat-item failure">
            <el-icon><Close /></el-icon>
            <span class="stat-label">失败</span>
            <span class="stat-value">{{ crawler.failure || 0 }}</span>
          </div>
          <div class="stat-item batch">
            <el-icon><Files /></el-icon>
            <span class="stat-label">当前批次</span>
            <span class="stat-value">{{ crawler.currentBatch || 0 }}</span>
          </div>
        </div>

        <!-- 成功率显示 -->
        <div class="success-rate-section" v-if="crawler.processed > 0">
          <div class="success-rate">
            成功率: {{ successRate }}%
          </div>
        </div>

        <!-- 操作按钮 -->
        <div class="progress-actions">
          <el-button 
            type="danger" 
            icon="VideoPause"
            @click="handleStopCrawler"
            :disabled="!crawlerRunning"
            :loading="stopCrawlerLoading"
          >
            {{ stopCrawlerLoading ? '正在停止...' : '停止爬虫' }}
          </el-button>
          
          <el-button 
            type="info"
            icon="Refresh"
            @click="refreshProgress"
            :disabled="refreshing"
          >
            {{ refreshing ? '刷新中...' : '手动刷新' }}
          </el-button>
        </div>

        <!-- 错误信息显示 -->
        <div class="error-section" v-if="crawler.error">
          <el-alert
            title="错误信息"
            :description="crawler.error"
            type="error"
            show-icon
            :closable="false">
          </el-alert>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script setup name="Related_links">
import { 
  listRelated_links, 
  getRelated_links, 
  delRelated_links, 
  updateRelated_links,
  startCrawler,
  stopCrawler,
  getCrawlerProgress
} from "@/api/related_links/related_links";
import { Clock, Check, Close, Files } from '@element-plus/icons-vue';

const { proxy } = getCurrentInstance();

// 响应式数据
const related_linksList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const crawlerProgressVisible = ref(false);
const crawlerRunning = ref(false);
const progressTimer = ref(null);
const stopCrawlerLoading = ref(false);
const refreshing = ref(false);
const currentTime = ref('');

// 表单数据
const queryParams = ref({
  pageNum: 1,
  pageSize: 10,
  topicId: null,
  createdTime: null,
  crawlStatus: null,
});

const form = ref({});

const rules = {
  topicId: [{ required: true, message: "热搜主题ID不能为空", trigger: "blur" }],
  relatedUrl: [{ required: true, message: "相关链接URL不能为空", trigger: "blur" }],
  crawlStatus: [{ required: true, message: "爬取状态不能为空", trigger: "change" }]
};

// 爬虫数据 - 初始化所有字段
const crawler = ref({
  total: 0,
  totalBatches: 0,
  currentBatch: 0,
  processed: 0,
  success: 0,
  failure: 0,
  status: 0,
  error: null
});

// 状态映射
const crawlStatusMap = {
  0: { type: 'warning', label: '未处理' },
  1: { type: 'success', label: '成功' },
  2: { type: 'danger', label: '失败' }
};

const statusConfig = {
  0: { type: 'info', label: '已停止' },
  1: { type: 'primary', label: '运行中' },
  2: { type: 'success', label: '已完成' },
  3: { type: 'info', label: '已停止' },
  4: { type: 'danger', label: '执行错误' }
};

// URL截断函数
const truncateUrl = (url) => {
  if (!url) return '';
  
  // 如果URL长度小于等于50个字符，直接返回
  if (url.length <= 50) {
    return url;
  }
  
  // 尝试智能截断：保留协议+域名+部分路径
  try {
    const urlObj = new URL(url);
    const protocol = urlObj.protocol; // http: 或 https:
    const hostname = urlObj.hostname; // 域名
    const pathname = urlObj.pathname; // 路径
    
    const baseUrl = `${protocol}//${hostname}`;
    const remainingLength = 50 - baseUrl.length - 3; // 3是"..."的长度
    
    if (remainingLength > 0 && pathname.length > 0) {
      const truncatedPath = pathname.substring(0, remainingLength);
      return `${baseUrl}${truncatedPath}...`;
    } else {
      // 如果域名本身就很长，只保留域名
      return baseUrl.length <= 47 ? baseUrl : `${baseUrl.substring(0, 47)}...`;
    }
  } catch (e) {
    // 如果URL解析失败，简单截断
    return url.substring(0, 47) + '...';
  }
};

// 复制到剪贴板函数
const copyToClipboard = async (text) => {
  try {
    // 优先使用现代的 Clipboard API
    if (navigator.clipboard && window.isSecureContext) {
      await navigator.clipboard.writeText(text);
    } else {
      // 降级方案：使用传统的 execCommand
      const textArea = document.createElement('textarea');
      textArea.value = text;
      textArea.style.position = 'fixed';
      textArea.style.left = '-999999px';
      textArea.style.top = '-999999px';
      document.body.appendChild(textArea);
      textArea.focus();
      textArea.select();
      document.execCommand('copy');
      textArea.remove();
    }
    
    proxy.$modal.msgSuccess('链接已复制到剪贴板');
  } catch (err) {
    console.error('复制失败:', err);
    proxy.$modal.msgError('复制失败，请手动复制');
  }
};

// 更新当前时间
const updateCurrentTime = () => {
  currentTime.value = new Date().toLocaleTimeString();
};

// 操作按钮配置
const actionButtons = computed(() => [
  {
    key: 'edit',
    type: 'success',
    plain: true,
    icon: 'Edit',
    label: '修改',
    disabled: single.value,
    handler: () => handleUpdate(),
    permission: ['related_links:related_links:edit']
  },
  {
    key: 'delete',
    type: 'danger',
    plain: true,
    icon: 'Delete',
    label: '删除',
    disabled: multiple.value,
    handler: () => handleDelete(),
    permission: ['related_links:related_links:remove']
  },
  {
    key: 'crawler',
    type: 'primary',
    plain: true,
    icon: 'Operation',
    label: crawlerRunning.value ? '爬虫运行中...' : '文章爬取',
    disabled: crawlerRunning.value,
    handler: handleStartCrawler,
    permission: ['related_links:related_links:crawler']
  }
]);

// 计算属性
const overallPercentage = computed(() => {
  if (!crawler.value.total || crawler.value.total <= 0) return 0;
  return Math.round((crawler.value.processed / crawler.value.total) * 100);
});

const progressStatus = computed(() => {
  if (crawler.value.status === 2) return 'success';
  if (crawler.value.status === 4) return 'exception';
  return '';
});

const successRate = computed(() => {
  if (!crawler.value.processed || crawler.value.processed <= 0) return '0.00';
  return ((crawler.value.success / crawler.value.processed) * 100).toFixed(2);
});

// 基础方法
const getList = () => {
  loading.value = true;
  listRelated_links(queryParams.value).then(response => {
    related_linksList.value = response.rows;
    total.value = response.total;
    loading.value = false;
  }).catch(error => {
    loading.value = false;
    console.error('获取列表失败:', error);
  });
};

const resetForm = () => {
  form.value = {};
  proxy.resetForm("related_linksRef");
};

const handleQuery = () => {
  queryParams.value.pageNum = 1;
  getList();
};

const resetQuery = () => {
  proxy.resetForm("queryRef");
  handleQuery();
};

const handleSelectionChange = (selection) => {
  single.value = selection.length !== 1;
  multiple.value = !selection.length;
};

const handleUpdate = (row) => {
  resetForm();
  const id = row?.id;
  if (id) {
    getRelated_links(id).then(response => {
      form.value = response.data;
      open.value = true;
      title.value = "修改相关链接";
    });
  }
};

const submitForm = () => {
  proxy.$refs["related_linksRef"].validate(valid => {
    if (valid) {
      updateRelated_links(form.value).then(() => {
        proxy.$modal.msgSuccess("修改成功");
        open.value = false;
        getList();
      });
    }
  });
};

const handleDelete = (row) => {
  const id = row?.id;
  if (id) {
    proxy.$modal.confirm(`是否确认删除相关链接编号为"${id}"的数据项？`).then(() => {
      return delRelated_links(id);
    }).then(() => {
      getList();
      proxy.$modal.msgSuccess("删除成功");
    });
  }
};

const cancel = () => {
  open.value = false;
  resetForm();
};

// 爬虫相关方法
const handleStartCrawler = () => {
  // 重置爬虫数据
  crawler.value = {
    total: 0,
    totalBatches: 0,
    currentBatch: 0,
    processed: 0,
    success: 0,
    failure: 0,
    status: 0,
    error: null
  };

  startCrawler().then(response => {
    console.log('启动爬虫响应:', response);
    
    if (response.code === 200) {
      crawlerRunning.value = true;
      crawlerProgressVisible.value = true;
      
      // 更安全地更新爬虫数据
      if (response.data && typeof response.data === 'object') {
        Object.keys(response.data).forEach(key => {
          if (crawler.value.hasOwnProperty(key)) {
            crawler.value[key] = response.data[key];
          }
        });
      }
      
      // 立即开始轮询
      startProgressPolling();
      proxy.$modal.msgSuccess('爬虫启动成功');
      
      console.log('爬虫启动后的状态:', crawler.value);
    } else {
      proxy.$modal.msgError(response.msg || '启动爬虫失败');
    }
  }).catch(error => {
    console.error('启动爬虫失败:', error);
    proxy.$modal.msgError(error.message || '启动爬虫失败');
    crawlerRunning.value = false;
  });
};

const handleStopCrawler = () => {
  proxy.$modal.confirm('确认停止爬虫任务？').then(() => {
    stopCrawlerLoading.value = true;
    
    stopCrawler().then(response => {
      console.log('停止爬虫响应:', response);
      
      if (response.code === 200) {
        stopProgressPolling();
        crawlerRunning.value = false;
        crawler.value.status = 3;
        proxy.$modal.msgSuccess('爬虫已停止');
        
        // 只刷新列表，不关闭弹窗
        getList();
      } else {
        proxy.$modal.msgError(response.msg || '停止爬虫失败');
      }
    }).catch(error => {
      console.error('停止爬虫失败:', error);
      proxy.$modal.msgError(error.message || '停止爬虫失败');
    }).finally(() => {
      stopCrawlerLoading.value = false;
    });
  });
};

const handleProgressDialogClose = () => {
  if (crawlerRunning.value) {
    proxy.$modal.confirm('爬虫正在运行中，确认关闭将停止爬虫任务？').then(() => {
      handleStopCrawler();
    }).catch(() => {
      // 用户取消关闭，保持弹窗打开
      return false;
    });
  } else {
    stopProgressPolling();
    crawlerProgressVisible.value = false;
  }
};

// 手动刷新进度
const refreshProgress = () => {
  if (refreshing.value) return;
  
  refreshing.value = true;
  getCrawlerProgress().then(response => {
    console.log('手动刷新进度响应:', response);
    
    if (response.code === 200 && response.data) {
      updateCrawlerProgress(response.data);
      proxy.$modal.msgSuccess('进度已刷新');
    }
  }).catch(error => {
    console.error('刷新进度失败:', error);
    proxy.$modal.msgError('刷新进度失败');
  }).finally(() => {
    refreshing.value = false;
  });
};

// 更新爬虫进度的统一方法
const updateCrawlerProgress = (data) => {
  console.log('更新进度数据:', data);
  
  // 安全地更新每个字段
  Object.keys(data).forEach(key => {
    if (crawler.value.hasOwnProperty(key)) {
      // 确保数字类型正确转换
      if (['total', 'totalBatches', 'currentBatch', 'processed', 'success', 'failure', 'status'].includes(key)) {
        crawler.value[key] = Number(data[key]) || 0;
      } else {
        crawler.value[key] = data[key];
      }
    }
  });
  
  console.log('更新后的爬虫状态:', crawler.value);
  
  // 更新时间
  updateCurrentTime();
};

// 进度轮询
const startProgressPolling = () => {
  console.log('开始进度轮询');
  
  // 清除之前的定时器
  if (progressTimer.value) {
    clearInterval(progressTimer.value);
  }
  
  // 立即执行一次
  fetchProgress();
  
  // 设置定时器，每秒轮询一次
  progressTimer.value = setInterval(() => {
    fetchProgress();
  }, 1000);
};

const fetchProgress = () => {
  getCrawlerProgress().then(response => {
    console.log('轮询进度响应:', response);
    
    if (response.code === 200 && response.data) {
      updateCrawlerProgress(response.data);
      
      // 检查是否完成或出错
      const status = Number(response.data.status);
      if ([2, 4].includes(status)) {
        // 完成或出错，停止轮询
        stopProgressPolling();
        crawlerRunning.value = false;
        
        const msg = status === 2 ? '爬虫任务已完成！' : '爬虫任务执行出错';
        const msgType = status === 2 ? 'msgSuccess' : 'msgError';
        proxy.$modal[msgType](msg);
        
        // 只刷新列表，不关闭弹窗
        getList();
        
      } else if (status === 3) {
        // 已停止
        stopProgressPolling();
        crawlerRunning.value = false;
      }
    }
  }).catch(error => {
    console.error('获取进度失败:', error);
    // 连续失败多次则停止轮询
    if (!crawler.value.errorCount) {
      crawler.value.errorCount = 0;
    }
    crawler.value.errorCount++;
    
    if (crawler.value.errorCount > 5) {
      console.error('进度轮询连续失败，停止轮询');
      stopProgressPolling();
      crawlerRunning.value = false;
      proxy.$modal.msgError('获取进度失败，请手动刷新');
    }
  });
};

const stopProgressPolling = () => {
  console.log('停止进度轮询');
  
  if (progressTimer.value) {
    clearInterval(progressTimer.value);
    progressTimer.value = null;
  }
};

// 生命周期
onMounted(() => {
  getList();
  // 初始化时间显示
  updateCurrentTime();
});

onBeforeUnmount(() => {
  stopProgressPolling();
});

// 组件被激活时检查爬虫状态
onActivated(() => {
  // 页面重新激活时检查是否有运行中的爬虫
  getCrawlerProgress().then(response => {
    if (response.code === 200 && response.data && response.data.status === 1) {
      crawlerRunning.value = true;
      updateCrawlerProgress(response.data);
      if (!progressTimer.value) {
        startProgressPolling();
      }
    }
  }).catch(error => {
    console.error('检查爬虫状态失败:', error);
  });
});
</script>

<style scoped>
.progress-container {
  padding: 20px;
}

.status-section {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding: 10px;
  background-color: #f5f7fa;
  border-radius: 4px;
}

.status-time {
  font-size: 12px;
  color: #909399;
}

.progress-section {
  margin-bottom: 20px;
}

.progress-section h4 {
  margin: 0 0 10px 0;
  font-size: 14px;
  color: #303133;
}

.progress-text {
  margin-top: 10px;
  font-size: 12px;
  color: #606266;
  text-align: center;
}

.stats-section {
  display: flex;
  justify-content: space-around;
  margin-bottom: 20px;
  padding: 15px;
  background-color: #fafafa;
  border-radius: 4px;
}

.stat-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
}

.stat-item.success {
  color: #67c23a;
}

.stat-item.failure {
  color: #f56c6c;
}

.stat-item.batch {
  color: #409eff;
}

.stat-label {
  font-size: 12px;
  color: #909399;
}

.stat-value {
  font-size: 18px;
  font-weight: bold;
}

.success-rate-section {
  text-align: center;
  margin-bottom: 20px;
}

.success-rate {
  display: inline-block;
  padding: 5px 15px;
  background-color: #e1f3d8;
  color: #67c23a;
  border-radius: 12px;
  font-weight: bold;
}

.progress-actions {
  display: flex;
  justify-content: center;
  gap: 10px;
  padding-top: 15px;
  border-top: 1px solid #EBEEF5;
}

.error-section {
  margin-top: 15px;
}

/* 新增的URL容器样式 */
.url-container {
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: 100%;
}

.url-text {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: #606266;
  font-size: 13px;
  cursor: pointer;
}

.url-text:hover {
  color: #409eff;
}

.copy-btn {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  padding: 0;
  font-size: 12px;
  opacity: 0.7;
  transition: opacity 0.3s;
}

.copy-btn:hover {
  opacity: 1;
}

/* 表格行悬停时显示复制按钮 */
.el-table__row:hover .copy-btn {
  opacity: 0.9;
}
</style>